package com.ruoyi.business.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ruoyi.business.domain.MroLogistics;
import com.ruoyi.business.domain.OrderInfo;
import com.ruoyi.business.domain.OrderInfoDetail;
import com.ruoyi.business.dto.CheckMorLogisticsDto;
import com.ruoyi.business.enums.SendInfoEnum;
import com.ruoyi.business.mapper.MroLogisticsMapper;
import com.ruoyi.business.mapper.OrderInfoDetailMapper;
import com.ruoyi.business.service.IMroLogisticsService;
import com.ruoyi.business.utils.BadRequestException;
import com.ruoyi.business.utils.CategoryUtil;
import com.ruoyi.business.utils.MyException;
import com.ruoyi.business.vo.LogisticsDetailVo;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 物流信息Service业务层处理
 *
 * @author wyb
 * @date 2025-07-28
 */
@Service
public class MroLogisticsServiceImpl implements IMroLogisticsService {
    @Autowired
    private MroLogisticsMapper mroLogisticsMapper;

    @Autowired
    private Snowflake snowflake;

    @Autowired
    private OrderInfoServiceImpl orderInfoService;

    @Autowired
    private OrderInfoDetailMapper orderInfoDetailMapper;

    @Autowired
    private CategoryUtil categoryUtil;

    /**
     * 查询物流信息
     *
     * @param deliveryNo 物流信息主键
     * @return 物流信息
     */
    @Override
    public MroLogistics selectMroLogisticsByDeliveryNo(String deliveryNo) {
        return mroLogisticsMapper.selectMroLogisticsByDeliveryNo(deliveryNo);
    }

    /**
     * 查询物流信息列表
     *
     * @param mroLogistics 物流信息
     * @return 物流信息
     */
    @Override
    public List<MroLogistics> selectMroLogisticsList(MroLogistics mroLogistics) {
        return mroLogisticsMapper.selectMroLogisticsList(mroLogistics);
    }

    /**
     * 新增物流信息
     *
     * @param mroLogistics 物流信息
     * @return 结果
     */
    @Override
    public int insertMroLogistics(MroLogistics mroLogistics) {
        //1.物流主键id,防重校验
        if (this.checkMroLogisticsUnique(mroLogistics) == false) {
            throw new MyException("物流主键重复,无法插入");
        }
        //2.判空
        if (mroLogistics.getOrderNo() == null || mroLogistics.getOuterOrderNo() == null || mroLogistics.getNumber() == null) {
            throw new MyException("微盟订单号或者订单编号或者快递单号不能为空");
        }
        CheckMorLogisticsDto checkMorLogisticsDto = new CheckMorLogisticsDto();
        checkMorLogisticsDto.setNumber(mroLogistics.getNumber());
        checkMorLogisticsDto.setOrderNo(mroLogistics.getOrderNo());
        checkMorLogisticsDto.setOuterOrderNo(mroLogistics.getOuterOrderNo());
        // 3.根据 微盟订单号-orderNo  (2)dkId-outerOrderNo   3.快递单号number进行查重防重检查
        if (this.checkMroLogisticsByOrderNoAndDkIdAndNumberUnique(checkMorLogisticsDto)) {
            throw new MyException("已有物流，微盟订单号，快递单号，订单编号同时存在");
        }
        MroLogistics mls = new MroLogistics();
        mls.setDeliveryNo("wl" + Long.toString(snowflake.nextId()));
        mls.setOrderNo(mroLogistics.getOrderNo());
        mls.setNumber(mroLogistics.getNumber());
        //发货人详情
        mls.setSenderName(SendInfoEnum.SENDERNAME.getMessage()); //发货人姓名
        mls.setSenderMobile(SendInfoEnum.SENDERMOBILE.getMessage());//发货人手机号
        mls.setSenderAddress(SendInfoEnum.SENDERADDRESS.getMessage());

        String outerOrderNo = mroLogistics.getOuterOrderNo();
        mls.setOuterOrderNo(outerOrderNo);
        OrderInfo orderInfo = orderInfoService.selectOrderInfoByOuterOrderNo(outerOrderNo);
        if (orderInfo == null) {
            throw new MyException("订单为空,请重新输入正确的订单编号");
        }
        if (orderInfo.getStatus() == null) {
            throw new MyException("订单状态不能为空");
        } else if (orderInfo.getStatus().equals(1)) {
            throw new MyException("订单状态为草稿,请先发送订单");
        } else if (orderInfo.getStatus().equals(3)) {
            throw new MyException("订单状态为已发货,请先发送订单");
        } else if (orderInfo.getStatus().equals(4)) {
            throw new MyException("订单状态为已完成,导入失败");
        }


        //收货人详情
        mls.setAreaCode(SendInfoEnum.AREACODE.getMessage());//收件人所在乡镇/街道编码
        mls.setAddress(SendInfoEnum.ADDRESS.getMessage());//收件人的详细地址
        mls.setArea(SendInfoEnum.AREA.getMessage());//收件人的乡镇/街道
        mls.setZip(SendInfoEnum.ZIP.getMessage());//收件人邮编
        mls.setCountyCode(SendInfoEnum.COUNTYCODE.getMessage());//收件人所在区/县编码
        mls.setCityCode(SendInfoEnum.CITYCODE.getMessage());//收件人所在城市编码
        mls.setProvinceCode(SendInfoEnum.PROVINCECODE.getMessage());//收件人所在省份编码
        mls.setProvince(SendInfoEnum.PROVINCE.getMessage());//收件人的省
        mls.setCity(SendInfoEnum.CITY.getMessage());//收件人的城市
        mls.setLatitude(SendInfoEnum.LATITUDE.getMessage());//收件人维度
        mls.setCounty(SendInfoEnum.COUNTY.getMessage());//收件人的区/县
        mls.setLongitude(SendInfoEnum.LONGITUDE.getMessage());//收件人经度
        //dkId?
        mls.setWriteOffId(1l);
        mls.setDeliveryMethod(1l);
        List<OrderInfoDetail> orderInfoDetails = orderInfoDetailMapper.selectOrderInfoDetailByOuterOrderNo(orderInfo.getOuterOrderNo());
        if (orderInfoDetails == null) {
            throw new MyException("没有订单详情");
        }

        if (mroLogistics.getStatus() == null || mroLogistics.getStatus() != 99) {
            String outItemIds = orderInfoDetails.stream().map(OrderInfoDetail::getOutitemId)
                    .collect(Collectors.joining(","));
            mls.setOutItemId(outItemIds);
            String skuNum = orderInfoDetails.stream().map(OrderInfoDetail::getSkuNum)
                    .map(String::valueOf)
                    .collect(Collectors.joining(","));
            mls.setSkuNum(skuNum);//"从订单表查出来的数量,进行拼接"
        } else if (mroLogistics.getStatus() == 99l && mroLogistics.getStatus() != null) {
            mls.setOutItemId(mroLogistics.getOutItemId());
            mls.setSkuNum(mroLogistics.getSkuNum());
        }

        mls.setReceiverAddress(orderInfo.getAddress());//收件人地址
        mls.setReceiverName(orderInfo.getReceiverName());//收件人姓名
        mls.setReceiverMobile(orderInfo.getReceiverMobile());//收件人手机号
        mls.setCompanyCode(mroLogistics.getCompanyName());//数据字典
        String label = categoryUtil.getDictLabel("sys_logistics_company", mroLogistics.getCompanyName());//拿到label值
        categoryUtil.validateCategory(label);//校验物流名称
        mls.setCompanyName(label);
        //固定字段
        mls.setProcessVid(SendInfoEnum.PROCESSVID.getMessage());
        mls.setProcessVidName(SendInfoEnum.PROCESSVIDNAME.getMessage());
        mls.setOrderStatus(Long.parseLong(SendInfoEnum.ORDERSTATUS.getMessage()));
        //草稿状态
        mls.setStatus(0l);
        mls.setCreateTime(DateUtils.getNowDate());
        mls.setCreateBy(SecurityUtils.getLoginUser().getUser().getNickName());
        return mroLogisticsMapper.insertMroLogistics(mls);
    }

    /**
     * 修改物流信息
     *
     * @param mroLogistics 物流信息
     * @return 结果
     */
    @Override
    public int updateMroLogistics(MroLogistics mroLogistics) {
        return mroLogisticsMapper.updateMroLogistics(mroLogistics);
    }

    /**
     * 批量删除物流信息
     *
     * @param deliveryNos 需要删除的物流信息主键
     * @return 结果
     */
    @Override
    public int deleteMroLogisticsByDeliveryNos(String[] deliveryNos) {
        int count = 0;
        // 检查所有物流状态是否为草稿
        for (String deliveryNo : deliveryNos) {
            MroLogistics mroLogistics = mroLogisticsMapper.selectMroLogisticsByDeliveryNo(deliveryNo);
            if (mroLogistics == null) {
                throw new RuntimeException("物流不存在: " + deliveryNo);
            }
            if (mroLogistics.getStatus() != 0) {
                throw new RuntimeException("物流状态不为草稿，无法删除");
            }
            int i = mroLogisticsMapper.deleteMroLogisticsByOuterOrderNo(mroLogistics.getOuterOrderNo());
            count = count + i;
        }
        return count;
        //mroLogisticsMapper.deleteMroLogisticsByDeliveryNos(deliveryNos)
    }

    /**
     * 删除物流信息信息
     *
     * @param deliveryNo 物流信息主键
     * @return 结果
     */
    @Override
    public int deleteMroLogisticsByDeliveryNo(String deliveryNo) {
        // 检查物流状态是否为0
        MroLogistics mroLogistics = mroLogisticsMapper.selectMroLogisticsByDeliveryNo(deliveryNo);
        if (mroLogistics == null) {
            throw new RuntimeException("物流不存在: " + deliveryNo);
        }
        if (mroLogistics.getStatus() != 0) {
            throw new RuntimeException("物流状态不为草稿，无法删除");
        }
        //mroLogisticsMapper.deleteMroLogisticsByDeliveryNo(deliveryNo)
        return mroLogisticsMapper.deleteMroLogisticsByOuterOrderNo(mroLogistics.getOuterOrderNo());
    }

    /*防重校验*/
    @Override
    public boolean checkMroLogisticsUnique(MroLogistics mroLogistics) {
        MroLogistics mr = mroLogisticsMapper.checkMroLogisticsUnique(mroLogistics.getDeliveryNo());
        //没有相同的
        if (mr == null) {
            return UserConstants.UNIQUE;
        }
        return UserConstants.NOT_UNIQUE;
    }

    @Override
    public boolean checkMroLogisticsByOrderNoAndDkIdAndNumberUnique(CheckMorLogisticsDto checkMorLogisticsDto) {
        return mroLogisticsMapper.checkMroLogisticsByOrderNoAndDkIdAndNumberUnique(checkMorLogisticsDto);
    }

    @Transactional
    @Override
    public void batchInsertOrUpdateByImport(List<MroLogistics> saveList) {
        if (CollectionUtils.isEmpty(saveList)) {
            throw new BadRequestException("导入数据不能为空！");
        }
        //判断 代客ID和微盟ID一对一匹配关系
        List<OrderInfoDetail> details = new ArrayList<OrderInfoDetail>();
        // 2. 按微盟订单号分组 , 检查是否有多个 outerOrderNo 对应同一个 orderNo
        Map<String, Set<Long>> groupByOrderNo = saveList.stream()
                .collect(Collectors.groupingBy(MroLogistics::getOuterOrderNo, Collectors.mapping(MroLogistics::getOrderNo, Collectors.toSet())));
        for (Map.Entry<String, Set<Long>> entry : groupByOrderNo.entrySet()) {
            String outerOrderNo = entry.getKey();
            Set<Long> orderNos = entry.getValue();
            if (orderNos.size() > 1) {
                throw new MyException("同一个 代客订单号 [" + outerOrderNo + "] 对应多个 微盟号: " + orderNos + "请检查！");
            }
        }

        //判断 微盟ID和代客ID一对一匹配关系
        Map<Long, Set<String>> groupByOuterOrderNo = saveList.stream()
                .collect(Collectors.groupingBy(
                        MroLogistics::getOrderNo,
                        Collectors.mapping(MroLogistics::getOuterOrderNo, Collectors.toSet())
                ));
        for (Map.Entry<Long, Set<String>> entry : groupByOuterOrderNo.entrySet()) {
            Long orderNo = entry.getKey();
            Set<String> outerOrderNos = entry.getValue();
            if (outerOrderNos.size() > 1) {
                throw new BadRequestException("同一个 微盟号 [" + orderNo + "] 对应多个 代客订单号: " + outerOrderNos + "请检查！");
            }
        }
        // 2. 按dkId分组
        Map<String, List<MroLogistics>> detailMap = saveList.stream()
                .collect(Collectors.groupingBy(MroLogistics::getOuterOrderNo));
        //根据所有的dkId，查询所有的details集合
        for (Map.Entry<String, List<MroLogistics>> entry : detailMap.entrySet()) {
            //外部订单号DK
            String outerOrderNo = entry.getKey();

            //判断
            List<MroLogistics> logisticsInfoByOuterOrderNoList = mroLogisticsMapper.getLogisticsListByOuterOrderNo(outerOrderNo);
            if(CollectionUtils.isNotEmpty(logisticsInfoByOuterOrderNoList) &&  logisticsInfoByOuterOrderNoList.get(0).getStatus()!=0){
                throw new BadRequestException("代客订单编号为："+outerOrderNo+"的物流状态非草稿，导入失败！");
            }
            mroLogisticsMapper.deleteMroLogisticsByOuterOrderNo(outerOrderNo);
            //获取每个dk下的所有明细
            List<OrderInfoDetail> orderInfoDetails = orderInfoDetailMapper.selectOrderInfoDetailByOuterOrderNo(outerOrderNo);
            details.addAll(orderInfoDetails);
        }
        List<MroLogistics> mroLogistics = this.allocateOrders(details, saveList);
        for (MroLogistics mroLogistics1 : mroLogistics) {
            this.insertMroLogistics(mroLogistics1);
        }
    }

    @Override
    public MroLogistics selectLogisticsInfoByDeliveryNo(String deliveryNo) {
        return mroLogisticsMapper.selectMroLogisticsByDeliveryNo(deliveryNo);
    }

    @Override
    public List<LogisticsDetailVo> getLogisticsInfoByOuterOrderNo(String outerOrderNo) {
        List<MroLogistics> detailList = mroLogisticsMapper.getLogisticsInfoByOuterOrderNo(outerOrderNo);
        return detailList.stream().map(item -> {
            LogisticsDetailVo vo = new LogisticsDetailVo();
            vo.setNumber(item.getNumber());
            vo.setCompanyName(item.getCompanyName());
            return vo;
        }).collect(Collectors.toList());
    }


    @Override
    public List<MroLogistics> distinctList(MroLogistics mroLogistics) {
        return mroLogisticsMapper.distinctList(mroLogistics);
    }

    /**
     * 分配订单到物流
     *
     * @param orderInfoDetails 订单详情列表
     * @param logisticsList    预定义的物流对象列表
     * @return 分配后的物流列表
     */
    public List<MroLogistics> allocateOrders(List<OrderInfoDetail> orderInfoDetails, List<MroLogistics> logisticsList) {
        if (orderInfoDetails == null || logisticsList == null) {
            throw new MyException("订单详情列表和物流列表不能为null");
        }
        if (orderInfoDetails.isEmpty() || logisticsList.isEmpty()) {
            throw new MyException("订单详情列表和物流列表不能为空");
        }
        //对logisticsList通过outer_order_no进行分组：同一个订单会出现多个物流
        Map<String, List<MroLogistics>> logisticsMap = logisticsList.stream()
                .collect(Collectors.groupingBy(MroLogistics::getOuterOrderNo));

        //对商品详情通过outer_order_no进行分组
        Map<String, List<OrderInfoDetail>> detailMap = orderInfoDetails.stream()
                .collect(Collectors.groupingBy(OrderInfoDetail::getOuterOrderNo));

        for (Map.Entry<String, List<MroLogistics>> entry : logisticsMap.entrySet()) {
            //外部订单号DK
            String outerOrderNo = entry.getKey();
            //获取每个dk下的所有商品
            List<OrderInfoDetail> orderInfoDetailList = detailMap.get(outerOrderNo);
            //每个OrderInfoDetail里的SkuNum 是大于0的整数，至少为1
            int totalSkuNum = orderInfoDetailList.stream()
                    .mapToInt(OrderInfoDetail::getSkuNum)
                    .sum();

            //物流值
            List<MroLogistics> logistics = entry.getValue();
            //将totalSkuNum 分给 logistics.size，totalSkuNum 不应该小于logistics.size
            int logisticsSize = logistics.size();

            if (logisticsSize > 0 && totalSkuNum >= logisticsSize) {
                //最少均分数
                int base = totalSkuNum / logisticsSize;
                // 多余的部分，均匀加到前面的几个物流上
                int remainder = totalSkuNum % logisticsSize;

                // 每个物流目标 SKU 数量
                int[] targets = new int[logisticsSize];
                for (int i = 0; i < logisticsSize; i++) {
                    targets[i] = base + (i < remainder ? 1 : 0);
                }

                // 遍历商品，按顺序拆分分配
                int detailIndex = 0;
                int detailRemain = orderInfoDetailList.get(0).getSkuNum();
                String curItemId = orderInfoDetailList.get(0).getOutitemId();

                for (int i = 0; i < logisticsSize; i++) {
                    int target = targets[i];
                    List<String> outItemIds = new ArrayList<>();
                    List<String> skuNums = new ArrayList<>();

                    while (target > 0 && detailIndex < orderInfoDetailList.size()) {
                        int assignCount = Math.min(target, detailRemain);
                        outItemIds.add(curItemId);
                        skuNums.add(String.valueOf(assignCount));

                        target -= assignCount;
                        detailRemain -= assignCount;

                        if (detailRemain == 0) {
                            detailIndex++;
                            if (detailIndex < orderInfoDetailList.size()) {
                                OrderInfoDetail next = orderInfoDetailList.get(detailIndex);
                                curItemId = next.getOutitemId();
                                detailRemain = next.getSkuNum();
                            }
                        }
                    }

                    MroLogistics mroLogistics = logistics.get(i);
                    mroLogistics.setOutItemId(String.join(",", outItemIds));
                    mroLogistics.setSkuNum(String.join(",", skuNums));
                }
            } else {
                throw new MyException(
                        "商品总数少于物流条数,请检查物流信息！" +
                                " outerOrderNo=" + outerOrderNo +
                                ", totalSkuNum=" + totalSkuNum +
                                ", logisticsSize=" + logisticsSize
                );
            }
        }
        //临时状态，代表时导入
        logisticsList.stream().forEach(item -> item.setStatus(99l));
        return logisticsList;
    }
}

